package com.magold.sprite;

import org.andengine.opengl.shader.ShaderProgram;
import org.andengine.opengl.shader.constants.ShaderProgramConstants;
import org.andengine.opengl.shader.exception.ShaderProgramLinkException;
import org.andengine.opengl.util.GLState;
import org.andengine.opengl.vbo.attribute.VertexBufferObjectAttributes;

import android.opengl.GLES20;

public class CircleShaderProgram extends ShaderProgram implements ShaderProgramConstants {
	private static CircleShaderProgram INSTANCE;

	public static final String VERTEXSHADER =
			"uniform mat4 " + UNIFORM_MODELVIEWPROJECTIONMATRIX + ";\n" +
			"uniform mat4 u_modelViewMatrix;\n" +
			
			"attribute vec4 " + ATTRIBUTE_POSITION + ";\n" +
			"attribute vec4 " + ATTRIBUTE_COLOR + ";\n" +
			"attribute vec2 " + ATTRIBUTE_TEXTURECOORDINATES + ";\n" +
			
			"varying vec4 " + VARYING_COLOR + ";\n" +
			"varying vec2 " + VARYING_TEXTURECOORDINATES + ";\n" +
			"varying vec4 curr_position;\n" +
			
			"void main() {\n" +
			"	" + VARYING_COLOR + " = " + ATTRIBUTE_COLOR + ";\n" +
			"	" + VARYING_TEXTURECOORDINATES + " = " + ATTRIBUTE_TEXTURECOORDINATES + ";\n" +
			
			"	curr_position = u_modelViewMatrix * a_position;" +
			
			"	gl_Position = " + UNIFORM_MODELVIEWPROJECTIONMATRIX + " * " + ATTRIBUTE_POSITION + ";\n" +
			"}";

	public static final String FRAGMENTSHADER =
			"precision mediump float;\n" +
			"uniform sampler2D " + UNIFORM_TEXTURE_0 + ";\n" +
			"uniform float u_radius;\n" +
			"uniform vec4 u_center;\n" +

			"varying vec4 curr_position;\n" +
			"varying lowp vec4 " + VARYING_COLOR + ";\n" +
			"varying mediump vec2 " + VARYING_TEXTURECOORDINATES + ";\n" +
			
			"void main() {\n" +
			"	if (distance(curr_position, u_center) > u_radius) {\n" +
			"		discard;" +
			"	} else {" +
			"		gl_FragColor = " + VARYING_COLOR + " * texture2D(" + UNIFORM_TEXTURE_0 + ", " + VARYING_TEXTURECOORDINATES + ");\n" +
			"  }" +
			"}";

	
	public static int sUniformMVPMatrixLocation = LOCATION_INVALID;
	public static int sUniformTexture0Location = LOCATION_INVALID;
	public static int sUniformCenterLocation = LOCATION_INVALID;
	public static int sUniformRadiusLocation = LOCATION_INVALID;
	public static int sUniformModelViewLocation = LOCATION_INVALID;

	public static CircleShaderProgram getInstance() {
		if(INSTANCE == null) {
			INSTANCE = new CircleShaderProgram();
		}
		
		return INSTANCE;
	}
	
	private CircleShaderProgram() {
		super(VERTEXSHADER, FRAGMENTSHADER);
	}
	
	@Override
	protected void link(final GLState pGLState) throws ShaderProgramLinkException {
		GLES20.glBindAttribLocation(mProgramID, ATTRIBUTE_POSITION_LOCATION, "a_position");
		GLES20.glBindAttribLocation(mProgramID, ATTRIBUTE_COLOR_LOCATION, "a_color");
		GLES20.glBindAttribLocation(mProgramID, ATTRIBUTE_TEXTURECOORDINATES_LOCATION, "a_textureCoordinates");

		super.link(pGLState);

		sUniformMVPMatrixLocation = getUniformLocation("u_modelViewProjectionMatrix");
		sUniformModelViewLocation = getUniformLocation("u_modelViewMatrix");
		sUniformTexture0Location = getUniformLocation("u_texture_0");
		
		sUniformCenterLocation = getUniformLocation("u_center");
		sUniformRadiusLocation = getUniformLocation("u_radius");
	}

	@Override
	public void bind(GLState pGLState, VertexBufferObjectAttributes pVertexBufferObjectAttributes) {
		super.bind(pGLState, pVertexBufferObjectAttributes);

		float[] mvp_matrix = pGLState.getModelViewProjectionGLMatrix();
		float[] mv_matrix = pGLState.getModelViewGLMatrix();
		GLES20.glUniformMatrix4fv(sUniformMVPMatrixLocation, 1, false, mvp_matrix, 0);
		GLES20.glUniformMatrix4fv(sUniformModelViewLocation, 1, false, mv_matrix, 0);
		GLES20.glUniform1i(sUniformTexture0Location, 0);
	}

}
